home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / doom / quake_ad.zip / HIPQW.ZIP / SRC / HIPITEMS.QC < prev    next >
Text File  |  1997-03-13  |  24KB  |  887 lines

  1. /* Items QuickC program
  2.    By Jim Dose'  9/13/96
  3.    Copyright (c)1996 Hipnotic Interactive, Inc.
  4.    All rights reserved.
  5.    Do not distribute.
  6. */
  7. float (entity targ) infront;
  8.  
  9. float UNDERWATER = 2;
  10.  
  11. /*
  12. ===============================================================================
  13.  
  14. HIPNOTIC ITEMS
  15.  
  16. ===============================================================================
  17. */
  18. //
  19. // hip_powerup_touch function
  20. //
  21. void() hip_powerup_touch =
  22. {
  23. local entity    stemp;
  24. local float        best;
  25.  
  26.     if (other.classname != "player")
  27.         return;
  28.     if (other.health <= 0)
  29.         return;
  30.  
  31.         sprint (other, PRINT_MEDIUM,"You got the ");
  32.         sprint (other, PRINT_MEDIUM,self.netname);
  33.         sprint (other,PRINT_MEDIUM,"\n");
  34.  
  35.     if (deathmatch)
  36.     {
  37.         self.mdl = self.model;
  38.  
  39. //      if ((self.classname == "item_artifact_invulnerability") ||
  40. //         (self.classname == "item_artifact_invisibility"))
  41. //         self.nextthink = time + 60*5;
  42. //      else
  43.       self.nextthink = time + 60;
  44.  
  45.         self.think = SUB_regen;
  46.     }
  47.  
  48.     sound (other, CHAN_VOICE, self.noise, 1, ATTN_NORM);
  49.     stuffcmd (other, "bf\n");
  50.     self.solid = SOLID_NOT;
  51.    other.items2 = other.items2 | self.items2;
  52.     self.model = string_null;
  53.  
  54. // do the apropriate action
  55.    if ( self.classname == "item_artifact_wetsuit" )
  56.     {
  57.         other.wetsuit_time = 1;
  58.         other.wetsuit_finished = time + 30;
  59.     }
  60.    if ( self.classname == "item_artifact_empathy_shields" )
  61.     {
  62.       other.empathy_time = 1;
  63.       other.empathy_finished = time + 30;
  64.     }
  65.  
  66.     activator = other;
  67.     SUB_UseTargets();                // fire all targets / killtargets
  68. };
  69.  
  70.  
  71. /*QUAKED item_artifact_wetsuit (0 .5 .8) (-16 -16 -24) (16 16 32)
  72. Player takes no damage from electrical attacks and swims faster for 30 seconds
  73. */
  74. void() item_artifact_wetsuit =
  75. {
  76.    self.touch = hip_powerup_touch;
  77.  
  78.    precache_model ("progs/wetsuit.mdl");
  79.    precache_sound ("misc/wetsuit.wav");
  80.    precache_sound ("misc/weton.wav");
  81.    precache_sound ("items/suit2.wav");
  82.    self.noise = "misc/weton.wav";
  83.    setmodel (self, "progs/wetsuit.mdl");
  84.     self.netname = "Wetsuit";
  85.    self.items2 = HIP_IT_WETSUIT;
  86.    setsize (self, '-16 -16 -24', '16 16 32');
  87.  
  88.     StartItem ();
  89. };
  90.  
  91. /*
  92. ===============================================================================
  93. //
  94. // Horn of Conjuring
  95. //
  96. ===============================================================================
  97. */
  98.  
  99. void() horn_touch =
  100. {
  101.     local    float amount;
  102.    local float value;
  103.  
  104.     if (other.classname != "player")
  105.         return;
  106.  
  107.    if (deathmatch)
  108.     {
  109.         self.mdl = self.model;
  110.  
  111.       self.nextthink = time + 60;
  112.  
  113.         self.think = SUB_regen;
  114.     }
  115.  
  116.     self.solid = SOLID_NOT;
  117.     self.model = string_null;
  118.    sprint (other, PRINT_MEDIUM,"You got the Horn of Conjuring\n");
  119.    sound (other, CHAN_VOICE, self.noise, 1, ATTN_NONE);
  120.     stuffcmd (other, "bf\n");
  121.    activator = other;
  122.    horn_active = 1;
  123.    horn_charmer = other;
  124.     SUB_UseTargets();                // fire all targets / killtargets
  125.    horn_active = 0;
  126. };
  127.  
  128. /*QUAKED item_hornofconjuring (0 .5 .8) (-16 -16 0) (16 16 32)
  129. Horn of Conjuring.
  130. You must make func_spawn entities connected to this entity
  131. to spawn the charmed creature.
  132. */
  133. void() item_hornofconjuring =
  134.    {
  135.    self.touch = horn_touch;
  136.  
  137.    precache_model("progs/horn.mdl");
  138.    precache_sound("hipitems/horn.wav");
  139.    setmodel(self, "progs/horn.mdl");
  140.    self.noise = "hipitems/horn.wav";
  141.    setsize (self, '-16 -16 0', '16 16 32');
  142.     StartItem ();
  143.    };
  144.  
  145. /*QUAKED item_artifact_empathy_shields (0 .5 .8) (-16 -16 0) (16 16 32)
  146. Empathy Shield.
  147. */
  148. void() item_artifact_empathy_shields =
  149.    {
  150.    self.touch = hip_powerup_touch;
  151.  
  152.    precache_model("progs/empathy.mdl");
  153.    precache_sound("hipitems/empathy.wav");
  154.    precache_sound("hipitems/empathy2.wav");
  155.    precache_sound ("items/suit2.wav");
  156.    setmodel(self, "progs/empathy.mdl");
  157.    self.noise = "hipitems/empathy.wav";
  158.    self.netname = "Empathy Shields";
  159.    self.items2 = HIP_IT_EMPATHY_SHIELDS;
  160.    setsize (self, '-16 -16 0', '16 16 32');
  161.     StartItem ();
  162.    };
  163. /*
  164. ===============================================================================
  165.  
  166. HIPNOTIC WEAPONS
  167.  
  168. ===============================================================================
  169. */
  170.  
  171. /*QUAKED weapon_mjolnir (0 .5 .8) (-16 -16 0) (16 16 32)
  172. */
  173.  
  174. void() weapon_mjolnir =
  175. {
  176.    precache_model ("progs/g_hammer.mdl");
  177.    setmodel (self, "progs/g_hammer.mdl");
  178.     self.weapon = 3;
  179.    self.netname = "Mjolnir";
  180.    self.items = IT_MJOLNIR;
  181.     self.touch = weapon_touch;
  182.     setsize (self, '-16 -16 0', '16 16 56');
  183.     StartItem ();
  184. };
  185.  
  186. /*QUAKED weapon_laser_gun (0 .5 .8) (-16 -16 0) (16 16 32)
  187. */
  188.  
  189. void() weapon_laser_gun =
  190. {
  191.    precache_model ("progs/g_laserg.mdl");
  192.    setmodel (self, "progs/g_laserg.mdl");
  193.     self.weapon = 3;
  194.    self.netname = "Laser Cannon";
  195.    self.items = IT_LASER_CANNON;
  196.    self.touch = weapon_touch;
  197.     setsize (self, '-16 -16 0', '16 16 56');
  198.     StartItem ();
  199. };
  200.  
  201. /*QUAKED weapon_proximity_gun (0 .5 .8) (-16 -16 0) (16 16 32)
  202. */
  203.  
  204. void() weapon_proximity_gun =
  205. {
  206.    precache_model ("progs/g_prox.mdl");
  207.    setmodel (self, "progs/g_prox.mdl");
  208.     self.weapon = 3;
  209.    self.netname = "Proximity Gun";
  210.    self.items = IT_PROXIMITY_GUN;
  211.    self.touch = weapon_touch;
  212.     setsize (self, '-16 -16 0', '16 16 56');
  213.     StartItem ();
  214. };
  215.  
  216. /*
  217. ===============================================================================
  218.  
  219. HIPNOTIC HAZARDS
  220.  
  221. ===============================================================================
  222. */
  223.  
  224. void() spikemine_Home =
  225.    {
  226.    local entity head;
  227.    local entity selected;
  228.    local float cur_dist;
  229.    local float head_dist;
  230.    local vector dir, vtemp;
  231.  
  232.    self.frame = self.frame + 1;
  233.    if (self.frame==9) self.frame = 0;
  234.    self.nextthink = time + 0.2;
  235.    self.think = spikemine_Home;
  236.  
  237. // look in our immediate vicinity
  238.  
  239.    if (self.search_time < time)
  240.       {
  241.       selected = world;
  242.       cur_dist = 2000;
  243.       head = findradius(self.origin, 2000);
  244.       while(head)
  245.          {
  246.          if(!(head.flags & FL_NOTARGET) && (head.flags & FL_CLIENT))
  247.             {
  248.             if (visible(head) && (head.health > 0))
  249.                {
  250.                head_dist = vlen(head.origin-self.origin);
  251.                if (head_dist < cur_dist)
  252.                   {
  253.                   selected = head;
  254.                   cur_dist = head_dist;
  255.                   }
  256.                }
  257.             }
  258.          head = head.chain;
  259.          }
  260. //      if (selected != world && selected != self.enemy)
  261.       if (selected != world)
  262.          sound (self, CHAN_VOICE, "hipitems/spikmine.wav", 1, ATTN_NORM);
  263.       self.enemy = selected;
  264.       self.search_time = time + 1.3;
  265.       }
  266.    if (self.enemy == world)
  267.       {
  268.       sound (self, CHAN_VOICE, "misc/null.wav", 1, ATTN_NORM);
  269.       self.velocity = '0 0 0';
  270.       return;
  271.       }
  272.    vtemp = self.enemy.origin + '0 0 10';
  273.     dir = normalize(vtemp - self.origin);
  274.    if (infront(self.enemy))
  275.       {
  276.       self.velocity = dir * (100);
  277.       }
  278.    else
  279.       {
  280.       self.velocity = dir * (200);
  281.       }
  282.    };
  283.  
  284. void() spikemine_Touch =
  285.    {
  286.    if (self.health>0)    
  287.       {
  288.       if (other.classname == "trap_spike_mine")
  289.          return;
  290.       if (other.classname == "missile")
  291.          return;
  292.       if (other.classname == "grenade")
  293.          return;
  294.       if (other.classname == "hiplaser")
  295.          return;
  296.       if (other.classname == "proximity_grenade")
  297.          return;
  298.  
  299.       T_Damage(self,self,self,self.health+10);
  300. //      killed_monsters = killed_monsters + 1;
  301. //      WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
  302.       }
  303. //   self.effects = self.effects | EF_MUZZLEFLASH;
  304.  
  305.    T_RadiusDamage (self, self, 110, world);
  306.     sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  307.  
  308.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  309.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  310.     WriteCoord (MSG_BROADCAST, self.origin_x);
  311.     WriteCoord (MSG_BROADCAST, self.origin_y);
  312.     WriteCoord (MSG_BROADCAST, self.origin_z);
  313.  
  314.    sound (self, CHAN_VOICE, "misc/null.wav", 1, ATTN_NORM);
  315.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  316.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  317.     WriteCoord (MSG_BROADCAST, self.origin_x);
  318.     WriteCoord (MSG_BROADCAST, self.origin_y);
  319.     WriteCoord (MSG_BROADCAST, self.origin_z);
  320.    };
  321.  
  322. /*
  323. spike_mine_first_think
  324. */
  325.  
  326. void() spike_mine_first_think =
  327.    {
  328.    self.think = spikemine_Home;
  329.    self.nextthink = time + 0.1;
  330.    self.search_time = 0;
  331.    self.takedamage = DAMAGE_AIM;
  332.     self.use = monster_use;
  333.    };
  334.  
  335. /*QUAKED trap_spike_mine (0 .5 .8) (-16 -16 0) (16 16 32)
  336. */
  337.  
  338. void() trap_spike_mine =
  339.    {
  340.    if (deathmatch)
  341.     {
  342.         remove(self);
  343.         return;
  344.     }
  345.    precache_model ("progs/spikmine.mdl");
  346.    precache_sound ("weapons/r_exp3.wav");
  347.    precache_sound ("hipitems/spikmine.wav");
  348.    precache_sound ("misc/null.wav");
  349.    setmodel (self, "progs/spikmine.mdl");
  350. //   setmodel (self, "progs/spike.mdl");
  351.    setsize (self, self.mins, self.maxs);
  352.    self.classname = "trap_spike_mine";
  353.    self.solid = SOLID_BBOX;
  354.    self.movetype = MOVETYPE_FLYMISSILE;
  355. //   setsize (self, '0 0 0', '0 0 0');
  356. //   self.avelocity = '-100 100 -100';
  357.    self.avelocity = '-50 100 150';
  358.    if (cvar("skill") <= 1)
  359.       self.health = 200;
  360.    else
  361.       self.health = 400;
  362.    self.frame = 0;
  363.    self.think = spike_mine_first_think;
  364.    self.touch = spikemine_Touch;
  365.    self.th_die = spikemine_Touch;
  366.    self.th_stand = spikemine_Home;
  367.    self.th_walk = spikemine_Home;
  368.    self.th_run = spikemine_Home;
  369.    self.th_melee = spikemine_Home;
  370.    self.th_missile = spikemine_Home;
  371.    self.nextthink = time + 0.2;
  372.    total_monsters = total_monsters + 1;
  373.    self.flags = self.flags | FL_MONSTER;
  374.    self.deathtype = "was blasted by a spike mine";
  375.    };
  376.  
  377. //============================================================================
  378. float LIGHTNING_RANDOM = 1;
  379. float LIGHTNING_BOOM = 2;
  380.  
  381. void() SpawnLightningThink =
  382.    {
  383.    if (time > self.delay)
  384.       {
  385.       remove(self);
  386.       return;
  387.       }
  388.    self.think = SpawnLightningThink;
  389.    if (checkclient())
  390.       {
  391.       WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  392.       WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  393.       WriteEntity (MSG_BROADCAST, self);
  394.       WriteCoord (MSG_BROADCAST, self.origin_x);
  395.       WriteCoord (MSG_BROADCAST, self.origin_y);
  396.       WriteCoord (MSG_BROADCAST, self.origin_z);
  397.       WriteCoord (MSG_BROADCAST, self.oldorigin_x);
  398.       WriteCoord (MSG_BROADCAST, self.oldorigin_y);
  399.       WriteCoord (MSG_BROADCAST, self.oldorigin_z);
  400.       }
  401.    LightningDamage(self.origin, self.oldorigin, self.lastvictim, self.dmg);
  402.    self.nextthink = time + 0.1;
  403.    };
  404.  
  405. void() trap_lightning_use =
  406.    {
  407.    local vector p1, p2;
  408.    local vector dir;
  409.    local float dst;
  410.    local float remainder;
  411.  
  412.    if (time >= self.pausetime)
  413.       {
  414.       if (self.spawnflags & LIGHTNING_BOOM)
  415.          sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  416.       else
  417.          sound (self, CHAN_AUTO, "weapons/lhit.wav", 1, ATTN_NORM);
  418.       if (self.classname == "trap_lightning_triggered")
  419.          self.pausetime = time + 0.1;
  420.       }
  421.    if (self.target)
  422.       {
  423.       p1 = self.origin;
  424.       p2 = self.enemy.origin;
  425.       }
  426.    else
  427.       {
  428.       makevectors (self.angles);
  429.       self.movedir = v_forward;
  430.       traceline (self.origin, self.origin + self.movedir*600, TRUE, self);
  431.       p1 = self.origin;
  432.       p2 = trace_endpos;
  433.       }
  434.    // fix up both ends of the lightning
  435.    // lightning bolts are 30 units long each
  436.    dir = normalize( p2-p1 );
  437.    dst = vlen(p2-p1);
  438.    dst = dst / 30.0;
  439.    remainder = dst - floor(dst);
  440.    if (remainder > 0)
  441.       {
  442.       remainder = remainder - 1;
  443.       // split half the remainder with the front and back
  444.       remainder = remainder * 15;
  445.       p1 = p1 + (remainder*dir);
  446.       p2 = p2 - (remainder*dir);
  447.       }
  448.    if (self.duration > 0.1)
  449.       {
  450.       local entity temp;
  451.  
  452.       temp = self;
  453.       self = spawn();
  454.       self.origin = p1;
  455.       self.oldorigin = p2;
  456.       self.lastvictim = temp;
  457.       self.dmg = temp.dmg;
  458.       self.delay = time + temp.duration;
  459.       SpawnLightningThink();
  460.       self = temp;
  461.       }
  462.    else if (checkclient())
  463.       {
  464.       WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  465.       WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  466.       WriteEntity (MSG_BROADCAST, self);
  467.       WriteCoord (MSG_BROADCAST, p1_x);
  468.       WriteCoord (MSG_BROADCAST, p1_y);
  469.       WriteCoord (MSG_BROADCAST, p1_z);
  470.       WriteCoord (MSG_BROADCAST, p2_x);
  471.       WriteCoord (MSG_BROADCAST, p2_y);
  472.       WriteCoord (MSG_BROADCAST, p2_z);
  473.       LightningDamage(p1, p2, self, self.dmg);
  474.       }
  475.    else
  476.       LightningDamage(p1, p2, self, self.dmg);
  477.    };
  478.  
  479. void() lightning_think =
  480.    {
  481.    local float timedelay;
  482.  
  483.    if (self.state)
  484.       {
  485.       trap_lightning_use();
  486.       }
  487.    if (self.cnt == 0)
  488.       {
  489.       if (self.spawnflags & LIGHTNING_RANDOM)
  490.          {
  491.          timedelay = self.wait*random();
  492.          }
  493.       else
  494.          {
  495.          timedelay = self.wait;
  496.          }
  497.       self.cnt = 1;
  498.       self.t_length = time + self.duration - 0.1;
  499.       self.pausetime = time + self.duration - 0.1;
  500.       if (self.pausetime  < time + 0.3)
  501.          self.pausetime = time + 0.3;
  502.       if (timedelay < self.duration)
  503.          timedelay = self.duration;
  504.       self.t_width = time + timedelay;
  505.       }
  506.    if (time >= self.t_length)
  507.       {
  508.       self.cnt = 0;
  509.       self.nextthink = self.t_width;
  510.       }
  511.    else
  512.       {
  513.       self.nextthink = time + 0.2;
  514.       }
  515.    };
  516.  
  517. void() lightning_firstthink =
  518.    {
  519.    local entity targ;
  520.    if (self.target)
  521.       {
  522.       targ = find(world,targetname,self.target);
  523.       self.dest = targ.origin;
  524.       self.enemy = targ;
  525.       }
  526.    self.think = SUB_Null;
  527.    self.nextthink = 0;
  528.    if (self.classname != "trap_lightning_triggered")
  529.       {
  530.       self.nextthink = self.huntingcharmer + self.wait + self.ltime;
  531.       self.think = lightning_think;
  532.       }
  533.    };
  534.  
  535. /*QUAKED trap_lightning_triggered (0 .5 .8) (-8 -8 -8) (8 8 8) random boom
  536. When triggered, fires lightning in the direction set in QuakeEd.
  537. "wait" how long to wait between blasts (1.0 default)
  538.        if in random mode wait is multiplied by random
  539. "dmg" how much damage lightning should inflict (30 default)
  540. "duration" how long each lightning attack should last (0.1 default)
  541. */
  542.  
  543. void() trap_lightning_triggered =
  544.    {
  545.    if (self.wait == 0)
  546.       self.wait = 1.0;
  547.    if (self.dmg == 0)
  548.       self.dmg = 30;
  549.    if (self.duration == 0)
  550.       self.duration = 0.1;
  551.    self.cnt = 0;
  552.    self.use = trap_lightning_use;
  553.    precache_sound ("weapons/lhit.wav");
  554.    precache_sound ("weapons/lstart.wav");
  555.    self.huntingcharmer = self.nextthink;
  556.    self.think = lightning_firstthink;
  557.    self.nextthink = time + 0.25;
  558.    self.deathtype = "is electrocuted";
  559.    };
  560.  
  561.  
  562. /*QUAKED trap_lightning (0 .5 .8) (-8 -8 -8) (8 8 8) random boom
  563. Continuously fire lightning.
  564. "wait" how long to wait between blasts (1.0 default)
  565.        if in random mode wait is multiplied by random
  566. "nextthink" delay before firing first lightning, so multiple traps can be stagered.
  567. "dmg" how much damage lightning should inflict (30 default)
  568. "duration" how long each lightning attack should last (0.1 default)
  569. */
  570. void() trap_lightning =
  571.    {
  572.    trap_lightning_triggered ();
  573.    self.state = 1;
  574.    };
  575.  
  576. void() trap_lightning_switched_use =
  577.    {
  578.    self.state = 1 - self.state;
  579.    if (self.state == 1)
  580.       self.nextthink = self.huntingcharmer;
  581.    };
  582. /*QUAKED trap_lightning_switched (0 .5 .8) (-8 -8 -8) (8 8 8) random boom
  583. Continuously fires lightning.
  584. "wait" how long to wait between blasts (1.0 default)
  585.        if in random mode wait is multiplied by random
  586. "nextthink" delay before firing first lightning, so multiple traps can be stagered.
  587. "dmg" how much damage lightning should inflict (30 default)
  588. "duration" how long each lightning attack should last (0.1 default)
  589. "state" 0 (default) initially off, 1 initially on.
  590. */
  591. void() trap_lightning_switched =
  592.    {
  593.    trap_lightning_triggered ();
  594.    self.use = trap_lightning_switched_use;
  595.    };
  596.  
  597.  
  598. entity tesla_target;
  599. float tesla_numtargets;
  600. void() trap_tesla_scan =
  601.    {
  602.    local entity head;
  603.    local entity prev;
  604.  
  605. // look in our immediate vicinity
  606.  
  607.    tesla_numtargets = 0;
  608.    head = findradius(self.origin, self.distance);
  609.    while(head)
  610.       {
  611.       if(!(head.flags & FL_NOTARGET) && (head.flags & self.cnt))
  612.          {
  613.          if (visible(head) && (head.health > 0) && (head.struck_by_mjolnir==0))
  614.             {
  615.             if (tesla_numtargets == 0)
  616.                {
  617.                tesla_target = head;
  618.                }
  619.             else
  620.                {
  621.                prev.next_ent = head;
  622.                }
  623.             tesla_numtargets = tesla_numtargets + 1;
  624.             prev = head;
  625.             if (tesla_numtargets==self.count)
  626.                return;
  627.             }
  628.          }
  629.       head = head.chain;
  630.       }
  631.    };
  632.  
  633. void() TeslaLightningThink =
  634.    {
  635.    self.owner.attack_state = 2;
  636.    if (time > self.delay)
  637.       {
  638.       self.enemy.struck_by_mjolnir = 0;
  639.       remove(self);
  640.       return;
  641.       }
  642.    traceline (self.origin, self.enemy.origin, TRUE, self);
  643.  
  644.    if (trace_fraction != 1.0 || self.enemy.health<=0 || vlen(self.origin-self.enemy.origin) > (self.distance+10))
  645.       {
  646.       self.enemy.struck_by_mjolnir = 0;
  647.       remove(self);
  648.       return;
  649.       }
  650.    WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  651.    WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  652.    WriteEntity (MSG_BROADCAST, self);
  653.    WriteCoord (MSG_BROADCAST, self.origin_x);
  654.    WriteCoord (MSG_BROADCAST, self.origin_y);
  655.    WriteCoord (MSG_BROADCAST, self.origin_z);
  656.    WriteCoord (MSG_BROADCAST, trace_endpos_x);
  657.    WriteCoord (MSG_BROADCAST, trace_endpos_y);
  658.    WriteCoord (MSG_BROADCAST, trace_endpos_z);
  659.    LightningDamage(self.origin, trace_endpos, self.lastvictim, self.dmg);
  660.    self.nextthink = time + 0.1;
  661.    };
  662.  
  663. void(entity targ) SpawnTeslaLightning =
  664.    {
  665.    local entity lgt;
  666.    // spawn actual lightning
  667.    lgt = spawn();
  668.    if (self.duration>0)
  669.       {
  670.       lgt.delay = time + self.duration;
  671.       }
  672.    else
  673.       {
  674.       lgt.delay = time + 9999;
  675.       }
  676.    lgt.enemy = targ;
  677.    targ.struck_by_mjolnir = 1;
  678.    lgt.distance = self.distance;
  679.    lgt.owner = self;
  680.    lgt.lastvictim = self.lastvictim;
  681.    lgt.dmg = self.dmg;
  682.    lgt.origin = self.origin;
  683.    lgt.think = TeslaLightningThink;
  684.    lgt.nextthink = time;
  685.    lgt.deathtype = self.deathtype;
  686.    };
  687.  
  688. void() trap_tesla_think =
  689.    {
  690.    if (self.state == 0)
  691.       {
  692.       self.nextthink = time + 0.25;
  693.       return;
  694.       }
  695.    if (self.attack_state == 0)
  696.       {
  697.       self.think = trap_tesla_think;
  698.       trap_tesla_scan();
  699.       if (tesla_numtargets > 0)
  700.          {
  701.          if (self.wait > 0)
  702.             sound (self, CHAN_AUTO, "misc/tesla.wav", 1, ATTN_NORM);
  703.          self.attack_state = 1;
  704.          self.nextthink = time + self.wait;
  705.          return;
  706.          }
  707.       self.nextthink = time + 0.25;
  708.       if (self.delay > 0)
  709.          {
  710.          if (time > self.search_time)
  711.             {
  712.             self.attack_state = 3;
  713.             }
  714.          }
  715.       }
  716.    else if (self.attack_state == 1)
  717.       {
  718.       trap_tesla_scan();
  719.       while (tesla_numtargets > 0)
  720.          {
  721.          sound (self, CHAN_AUTO, "hipweap/mjolhit.wav", 1, ATTN_NORM);
  722.          SpawnTeslaLightning (tesla_target);
  723.          tesla_target = tesla_target.next_ent;
  724.          tesla_numtargets = tesla_numtargets - 1;
  725.          }
  726.       self.attack_state = 2;
  727.       self.nextthink = time + 1;
  728.       }
  729.    else if (self.attack_state == 2)
  730.       {
  731.       self.attack_state = 3;
  732.       self.nextthink = time + 0.2;
  733.       }
  734.    else if (self.attack_state == 3)
  735.       {
  736.       self.attack_state = 0;
  737.       self.nextthink = time + 0.1;
  738.       if (self.classname == "trap_gods_wrath")
  739.          {
  740.          self.nextthink = -1;
  741.          }
  742.       }
  743.    };
  744.  
  745. /*QUAKED trap_tesla_coil (0 .5 .8) (-8 -8 -8) (8 8 8) targetenemies
  746. targets enemies in vicinity and fires at them
  747. "wait" how long build up should be (2 second default)
  748. "dmg" how much damage lightning should inflict (2 + 5*skill default)
  749. "duration" how long each lightning attack should last (continuous default)
  750. "distance" how far the tesla coil should reach (600 default)
  751. "state" on/off for the coil (0 default is off)
  752. "count" number of people to target (2 default)
  753. */
  754. void() trap_tesla_coil =
  755.    {
  756.    precache_sound ("misc/tesla.wav");
  757.    precache_sound ("hipweap/mjolhit.wav");   // lightning sound
  758.    if (self.wait == 0)
  759.       self.wait = 2;
  760.    if (self.dmg == 0)
  761.       self.dmg = 2 + (5*cvar("skill"));
  762.    if (self.duration == 0)
  763.       self.duration = -1;
  764.    if (self.distance == 0)
  765.       self.distance = 600;
  766.    if (self.spawnflags & 1)
  767.       self.cnt = FL_CLIENT | FL_MONSTER;
  768.    else
  769.       self.cnt = FL_CLIENT;
  770.    self.use = trap_lightning_switched_use;
  771.    if (self.delay == 0)
  772.       self.delay = -1;
  773.    self.nextthink = time + random();
  774.    self.think = trap_tesla_think;
  775.    self.lastvictim = world;
  776.    tesla_numtargets = 0;
  777.    self.attack_state = 0;
  778.    self.deathtype = "is electrocuted";
  779.    };
  780.  
  781. void() trap_gods_wrath_use =
  782.    {
  783.    if (self.attack_state==0)
  784.       {
  785.       self.search_time = time + self.delay;
  786.       self.lastvictim = activator;
  787.       trap_tesla_think();
  788.       }
  789.    };
  790.  
  791. /*QUAKED trap_gods_wrath (0 .5 .8) (-8 -8 -8) (8 8 8) targetenemies
  792. targets enemies in vicinity and fires at them
  793. "dmg" how much damage lightning should inflict (5 default)
  794. "duration" how long each lightning attack should last (continuous default)
  795. "distance" how far god's wrath should reach (600 default)
  796. "delay" how long to wait until god calms down
  797.    this is only needed if no one is targetted (5 seconds default)
  798. "count" number of people to target (2 default)
  799. */
  800. void() trap_gods_wrath =
  801.    {
  802.    if (self.delay == 0)
  803.       self.delay = 5;
  804.    trap_tesla_coil();
  805.    self.wait = 0;
  806.    self.state = 1;
  807.    self.nextthink = -1;
  808.    self.deathtype = "suffers the wrath of God";
  809. //   self.attack_state = 1;
  810.    self.use = trap_gods_wrath_use;
  811.    };
  812.  
  813. void() trap_gravity_touch =
  814.    {
  815.    if ( self.attack_finished > time )
  816.       return;
  817.  
  818.    if (other.takedamage)
  819.       {
  820.       T_Damage (other, self, self, self.dmg );
  821.       self.attack_finished = time + 0.2;
  822.       }
  823.    };
  824.  
  825. void() trap_gravity_think =
  826.    {
  827.    local vector vel;
  828.    local vector dir;
  829.    local vector delta;
  830.  
  831.    self.ltime = time;
  832.    trap_tesla_scan();
  833.    while (tesla_numtargets > 0)
  834.       {
  835.       delta = self.origin - tesla_target.origin;
  836.       dir = normalize( delta );
  837.       vel = dir * self.speed;
  838.       if ( ( tesla_target.wetsuit_finished > time ) &&
  839.          ( self.spawnflags & UNDERWATER ) )
  840.          {
  841.          vel = vel * 0.6;
  842.          }
  843.  
  844.       tesla_target.velocity = tesla_target.velocity + vel;
  845.       tesla_target = tesla_target.next_ent;
  846.       tesla_numtargets = tesla_numtargets - 1;
  847.       }
  848.    self.nextthink = time + 0.1;
  849.    };
  850.  
  851. /*QUAKED trap_gravity_well (.8 .5 0) (-8 -8 -8) (8 8 8) targetenemies UNDERWATER
  852. targets enemies in vicinity and draws them near, gibbing them on contact.
  853.  
  854. UNDERWATER cuts the pull in half for players wearing the wetsuit
  855.  
  856. "distance" how far the gravity well should reach (600 default)
  857. "count" number of people to target (2 default)
  858. "speed" is how strong the pull is. (210 default)
  859. "dmg" is how much damage to do each touch. (10000 default)
  860. */
  861. void() trap_gravity_well =
  862.    {
  863.    self.solid = SOLID_TRIGGER;
  864.    self.movetype = MOVETYPE_NONE;
  865.    setsize( self, '-16 -16 -16','16 16 16');
  866.    if ( self.dmg == 0 )
  867.       {
  868.       self.dmg = 10000;
  869.       }
  870.    if ( self.speed == 0 )
  871.       self.speed = 210;
  872.    if (self.distance == 0)
  873.       self.distance = 600;
  874.    if (self.spawnflags & 1)
  875.       self.cnt = FL_CLIENT | FL_MONSTER;
  876.    else
  877.       self.cnt = FL_CLIENT;
  878.  
  879.    self.attack_finished = 0;
  880.    self.think = trap_gravity_think;
  881.    self.touch = trap_gravity_touch;
  882.    self.lastvictim = world;
  883.    tesla_numtargets = 0;
  884.    self.nextthink = time + 0.1;
  885.    self.ltime = time;
  886.    };
  887.